{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Example: combining MOD file ion channels with rxd" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A version of this notebook may be run online via Google Colab at https://tinyurl.com/neuron-rxd-and-mod\n", " (make a copy or open in playground mode)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overview" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "NEURON's reaction-diffusion infrastructure can be used to readily allow intracellular concentrations to respond to currents generated in MOD files, as long as:\n", "\n", "- `nrn_region='i'` is specified for the `rxd.Region` (so that it knows it corresponds to the electrophysiology region of the inside of the cell), AND\n", "the name and charge of the ion/etc are given in the `rxd.Species` declaration.\n", "Satisfying the above two rules also allows MOD files to see intracellular concentrations.\n", "\n", "- 3D extracellular concentrations also interoperate with electrophysiology automatically as long as name and charge are specified.\n", "\n", "As a simple example, we consider a model with just a single point soma, of length and diameter 10 microns, with Hodgkin-Huxley kinetics (which uses the built in mod file `hh.mod`), and dynamic sodium (declared using rxd but without any additional kinetics)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup NEURON library and imports" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's import our usual NEURON libraries and definitions. Remember you can use either `um` or `µm` for micron." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "execution": { "iopub.execute_input": "2026-03-20T19:23:02.591284Z", "iopub.status.busy": "2026-03-20T19:23:02.591127Z", "iopub.status.idle": "2026-03-20T19:23:02.952411Z", "shell.execute_reply": "2026-03-20T19:23:02.951940Z" } }, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from neuron import n, rxd\n", "from neuron.units import mV, ms, um, mM\n", "\n", "## needed for standard run system\n", "n.load_file(\"stdrun.hoc\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now import `plotly`, a graphics library. (You could easily modify this code to use other graphics libraries like `matplotlib`, `plotnine`, or `bokeh`.)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2026-03-20T19:23:02.986137Z", "iopub.status.busy": "2026-03-20T19:23:02.985835Z", "iopub.status.idle": "2026-03-20T19:23:03.024058Z", "shell.execute_reply": "2026-03-20T19:23:03.023603Z" } }, "outputs": [], "source": [ "import plotly.graph_objects as go\n", "from plotly.subplots import make_subplots" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup the model" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2026-03-20T19:23:03.026281Z", "iopub.status.busy": "2026-03-20T19:23:03.026121Z", "iopub.status.idle": "2026-03-20T19:23:03.056953Z", "shell.execute_reply": "2026-03-20T19:23:03.056532Z" } }, "outputs": [], "source": [ "## define morphology\n", "soma = n.Section(name=\"soma\")\n", "soma.L = soma.diam = 10 * um\n", "\n", "## add ion channels (n.hh is built in, so always available)\n", "n.hh.insert(soma)\n", "\n", "## define cytosol. MUST specify nrn_region for concentrations to update\n", "cyt = rxd.Region([soma], name=\"cyt\", nrn_region=\"i\")\n", "\n", "## define sodium. MUST specify name and charge for concentrations to update\n", "na = rxd.Species(cyt, name=\"na\", charge=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, we could have written `n.hh.insert(soma.wholetree())` to put Hodgkin-Huxley channels everywhere in the cell that the soma is part of, but since there is only one section, this is not required." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's also add an excitatory synapse to receive events (these will trigger the cell to spike)." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2026-03-20T19:23:03.059095Z", "iopub.status.busy": "2026-03-20T19:23:03.058944Z", "iopub.status.idle": "2026-03-20T19:23:03.061751Z", "shell.execute_reply": "2026-03-20T19:23:03.061391Z" } }, "outputs": [], "source": [ "syn = n.ExpSyn(soma(0.5))\n", "syn.tau = 1 * ms\n", "syn.e = 0 * mV" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Add a stimulus" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The spike events themselves (two events, 15 ms apart starting at n.t=10*ms):" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2026-03-20T19:23:03.063448Z", "iopub.status.busy": "2026-03-20T19:23:03.063305Z", "iopub.status.idle": "2026-03-20T19:23:03.066309Z", "shell.execute_reply": "2026-03-20T19:23:03.065938Z" } }, "outputs": [], "source": [ "stim = n.NetStim()\n", "stim.interval = 15 * ms\n", "stim.number = 2\n", "stim.start = 10 * ms" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Send those events to our synapse:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2026-03-20T19:23:03.067986Z", "iopub.status.busy": "2026-03-20T19:23:03.067826Z", "iopub.status.idle": "2026-03-20T19:23:03.070666Z", "shell.execute_reply": "2026-03-20T19:23:03.070319Z" } }, "outputs": [], "source": [ "nc = n.NetCon(stim, syn)\n", "nc.weight[0] = 0.001" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup recording variables" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2026-03-20T19:23:03.072354Z", "iopub.status.busy": "2026-03-20T19:23:03.072205Z", "iopub.status.idle": "2026-03-20T19:23:03.075377Z", "shell.execute_reply": "2026-03-20T19:23:03.075030Z" } }, "outputs": [], "source": [ "t = n.Vector().record(n._ref_t)\n", "v = n.Vector().record(soma(0.5)._ref_v)\n", "na_vec = n.Vector().record(soma(0.5)._ref_nai)\n", "ina = n.Vector().record(soma(0.5)._ref_ina)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Initialize and run the simulation" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2026-03-20T19:23:03.077642Z", "iopub.status.busy": "2026-03-20T19:23:03.077063Z", "iopub.status.idle": "2026-03-20T19:23:03.089221Z", "shell.execute_reply": "2026-03-20T19:23:03.088833Z" } }, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n.finitialize(-65 * mV)\n", "n.continuerun(50 * ms)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot it" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2026-03-20T19:23:03.091095Z", "iopub.status.busy": "2026-03-20T19:23:03.090946Z", "iopub.status.idle": "2026-03-20T19:23:03.324201Z", "shell.execute_reply": "2026-03-20T19:23:03.323791Z" } }, "outputs": [ { "data": { "text/html": [ " \n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "